using System;
using PropertyExpression.Common;

namespace PropertyExpression.ReactiveRelation
{
    public static partial class Value
    {
        public static IPropertyBindContext<TCalcContext, TTarget, TProperty>
            Convert<TCalcContext, TSource, TTarget, TProperty>(
            this IPropertyBindContext<TCalcContext, TSource, TProperty> propertyBindContext,
            Func<TSource, TTarget> func)
        {
            return new PropertyBindContextConverter<TCalcContext, TSource, TTarget, TProperty>(
                propertyBindContext, func);
        }

        private class PropertyBindContextConverter<TCalcContext, TSource, TTarget, TProperty>
            : IPropertyBindContext<TCalcContext, TTarget, TProperty>
        {
            private readonly IPropertyBindContext<TCalcContext, TSource, TProperty> propertyBindContext;
            private readonly Func<TSource, TTarget> func;

            public PropertyBindContextConverter(
                IPropertyBindContext<TCalcContext, TSource, TProperty> propertyBindContext,
                Func<TSource, TTarget> func)
            {
                this.propertyBindContext = propertyBindContext;
                this.func = func;
            }

            public IPropertyValue<TResultProperty> GetPropertyValue<TResultProperty>(
                IPropertyExpressionProxy<TTarget, TResultProperty> propertyExpressionProxy)
            {
                return propertyBindContext.GetPropertyValue(
                    new ExpressionWrapperConverter<TSource, TTarget, TResultProperty>(
                        propertyExpressionProxy, func
                        )
                    );
            }

            public FuncCache FuncCache
            {
                get { return propertyBindContext.FuncCache; }
            }

            public TCalcContext CalcContext
            {
                get { return propertyBindContext.CalcContext; }
            }

            public IValue<TProperty> NotCalc()
            {
                return propertyBindContext.NotCalc();
            }

            public IValue<TProperty> GetStoredValue()
            {
                return propertyBindContext.GetStoredValue();
            }

            public TTarget Entity
            {
                get { return func(propertyBindContext.Entity); }
            }
        }
    }
}
